home *** CD-ROM | disk | FTP | other *** search
/ Freelog 115 / FreelogNo115-MaiJuin2013.iso / Internet / Filezilla Server / FileZilla_Server-0_9_41.exe / source / interface / UsersListCtrl.cpp < prev    next >
C/C++ Source or Header  |  2011-11-06  |  25KB  |  912 lines

  1. // FileZilla Server - a Windows ftp server
  2.  
  3. // Copyright (C) 2002-2004 - Tim Kosse <tim.kosse@gmx.de>
  4.  
  5. // This program is free software; you can redistribute it and/or
  6. // modify it under the terms of the GNU General Public License
  7. // as published by the Free Software Foundation; either version 2
  8. // of the License, or (at your option) any later version.
  9.  
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14.  
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software
  17. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. // UsersListCtrl.cpp: Implementierungsdatei
  20. //
  21.  
  22. #include "stdafx.h"
  23. #include "filezilla server.h"
  24. #include "UsersListCtrl.h"
  25. #include "mainfrm.h"
  26. #include "OutputFormat.h"
  27.  
  28. #if defined(_DEBUG) && !defined(MMGR)
  29. #define new DEBUG_NEW
  30. #undef THIS_FILE
  31. static char THIS_FILE[] = __FILE__;
  32. #endif
  33.  
  34. #define NUMCOLUMNS 6
  35. #define COLUMN_ID 0
  36. #define COLUMN_USER 1
  37. #define COLUMN_IP 2
  38. #define COLUMN_TRANSFERINIT 3
  39. #define COLUMN_TRANSFERPROGRESS 4
  40. #define COLUMN_TRANSFERSPEED 5
  41.  
  42. #define SPEED_MEAN_SECONDS 10
  43.  
  44. class CConnectionData
  45. {
  46. public:
  47.     CConnectionData()
  48.     {
  49.         for (int i = 1; i < NUMCOLUMNS; i++)
  50.             itemImages[i] = -1;
  51.         itemImages[0] = 5;
  52.  
  53.         ResetSpeed();
  54.     }
  55.  
  56.     ~CConnectionData() { }
  57.     int userid;
  58.     unsigned int port;
  59.     unsigned char transferMode;
  60.     CString physicalFile;
  61.     CString logicalFile;
  62.     __int64 totalSize;
  63.     __int64 currentOffset;
  64.     unsigned int speed;
  65.     
  66.     int listIndex;
  67.     CString columnText[NUMCOLUMNS];
  68.     int itemImages[NUMCOLUMNS];
  69.  
  70.     inline void AddBytes(int bytes)
  71.     {
  72.         *current_speed += bytes;
  73.         UpdateSpeed();
  74.     }
  75.     
  76.     inline void UpdateSpeed()
  77.     {
  78.         speed = 0;
  79.         int max = speedDidWrap ? SPEED_MEAN_SECONDS : (current_speed - speed_mean + 1);
  80.         for (int i = 0; i < max; i++)
  81.             speed += speed_mean[i];
  82.         speed /= max;
  83.     }
  84.  
  85.     inline void NextSpeed()
  86.     {
  87.         if (!*current_speed)
  88.             UpdateSpeed();
  89.  
  90.         if ((++current_speed - speed_mean) >= SPEED_MEAN_SECONDS)
  91.         {
  92.             speedDidWrap = true;
  93.             current_speed = speed_mean;
  94.         }
  95.         *current_speed = 0;
  96.     }
  97.  
  98.     inline void ResetSpeed()
  99.     {
  100.         speedDidWrap = false;
  101.         current_speed = speed_mean;
  102.         *current_speed = 0;
  103.     }
  104.  
  105. private:
  106.     unsigned int speed_mean[SPEED_MEAN_SECONDS];
  107.     unsigned int *current_speed;
  108.     bool speedDidWrap;
  109. };
  110.  
  111. /////////////////////////////////////////////////////////////////////////////
  112. // CUsersListCtrl
  113.  
  114. CUsersListCtrl::CUsersListCtrl(CMainFrame *pOwner)
  115. {
  116.     ASSERT(pOwner);
  117.     m_pOwner = pOwner;
  118.     m_sortColumn = 0;
  119.     m_sortDir = 0;
  120. }
  121.  
  122. CUsersListCtrl::~CUsersListCtrl()
  123. {
  124.     for (std::vector<CConnectionData*>::iterator iter = m_connectionDataArray.begin(); iter != m_connectionDataArray.end(); iter++)
  125.         delete *iter;
  126. }
  127.  
  128.  
  129. BEGIN_MESSAGE_MAP(CUsersListCtrl, CListCtrl)
  130.     //{{AFX_MSG_MAP(CUsersListCtrl)
  131.     ON_WM_CREATE()
  132.     ON_COMMAND(ID_USERVIEWCONTEXT_KICK, OnContextmenuKick)
  133.     ON_COMMAND(ID_USERVIEWCONTEXT_BAN, OnContextmenuBan)
  134.     ON_WM_CONTEXTMENU()
  135.     ON_WM_SIZE()
  136.     ON_WM_TIMER()
  137.     ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
  138.     ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnclick)
  139.     //}}AFX_MSG_MAP
  140. END_MESSAGE_MAP()
  141.  
  142. /////////////////////////////////////////////////////////////////////////////
  143. // Behandlungsroutinen fⁿr Nachrichten CUsersListCtrl 
  144.  
  145. int CUsersListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
  146. {
  147.     if (CListCtrl::OnCreate(lpCreateStruct) == -1)
  148.         return -1;
  149.     
  150.     m_ImageList.Create(IDB_TRANSFERINFO, 16, 6, RGB(255, 0, 255));
  151.     SetImageList(&m_ImageList, LVSIL_SMALL);
  152.  
  153.     SetExtendedStyle(LVS_EX_LABELTIP | LVS_EX_SUBITEMIMAGES | LVS_EX_FULLROWSELECT);
  154.  
  155.     InsertColumn(COLUMN_ID, _T("ID"), LVCFMT_RIGHT, 75);
  156.     InsertColumn(COLUMN_USER, _T("Account"), LVCFMT_LEFT, 150);
  157.     InsertColumn(COLUMN_IP, _T("IP"), LVCFMT_RIGHT, 100);
  158.     InsertColumn(COLUMN_TRANSFERINIT, _T("Transfer"), LVCFMT_LEFT, 250);
  159.     InsertColumn(COLUMN_TRANSFERPROGRESS, _T("Progress"), LVCFMT_RIGHT, 150);
  160.     InsertColumn(COLUMN_TRANSFERSPEED, _T("Speed"), LVCFMT_LEFT, 80);
  161.  
  162.     m_SortImg.Create( 8, 8, ILC_MASK, 3, 3 );
  163.     HICON Icon;
  164.     Icon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_EMPTY));
  165.     m_SortImg.Add(Icon);
  166.     Icon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_UP));
  167.     m_SortImg.Add(Icon);
  168.     Icon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDI_DOWN));
  169.     m_SortImg.Add(Icon);
  170.     m_SortImg.SetBkColor(CLR_NONE);
  171.  
  172.     CHeaderCtrl *header = GetHeaderCtrl( );
  173.     if (header)
  174.         header->SetImageList(&m_SortImg);
  175.  
  176.     m_nSpeedinfoTimer = SetTimer(232, 1000, 0);
  177.  
  178.     return 0;
  179. }
  180.  
  181. bool CUsersListCtrl::ProcessConnOp(unsigned char *pData, DWORD dwDataLength)
  182. {
  183.     int op = pData[1];
  184.  
  185.     if (op < 0 || op > 4)
  186.         return FALSE;
  187.  
  188.     if (dwDataLength < 6)
  189.         return FALSE;
  190.     
  191.     if (op == USERCONTROL_CONNOP_ADD)
  192.     {
  193.         int userid;
  194.         memcpy(&userid, pData + 2, 4);
  195.         CConnectionData* pConnectionData = new CConnectionData;
  196.         pConnectionData->currentOffset = 0;
  197.         pConnectionData->totalSize = -1;
  198.  
  199.         pConnectionData->userid = userid;
  200.  
  201.         unsigned int pos = 6;
  202.  
  203.         if (dwDataLength < 8)
  204.         {
  205.             delete pConnectionData;
  206.             return FALSE;
  207.         }
  208.  
  209.         unsigned int len = pData[pos] * 256 + pData[pos+1];
  210.         pos += 2;
  211.         if (pos+len > dwDataLength)
  212.         {
  213.             delete pConnectionData;
  214.             return FALSE;
  215.         }
  216.  
  217.         char* ip = new char[len + 1];
  218.         memcpy(ip, pData + pos, len);
  219.         ip[len] = 0;
  220.         pos += len;
  221. #ifdef _UNICODE
  222.         pConnectionData->columnText[COLUMN_IP] = ConvFromNetwork(ip);
  223. #else
  224.         pConnectionData->columnText[COLUMN_IP] = ConvToLocal(ConvFromNetwork(ip));
  225. #endif
  226.         delete [] ip;
  227.  
  228.         if ((pos+4) > dwDataLength)
  229.         {
  230.             delete pConnectionData;
  231.             return FALSE;
  232.         }
  233.         memcpy(&pConnectionData->port, pData + pos, 4);
  234.  
  235.         pConnectionData->columnText[COLUMN_ID].Format(_T("%06d"), userid);
  236.         m_connectionDataMap[userid] = pConnectionData;
  237.         pConnectionData->listIndex = m_connectionDataArray.size();
  238.         m_connectionDataArray.push_back(pConnectionData);
  239.  
  240.         pConnectionData->columnText[COLUMN_USER] = _T("(not logged in)");
  241.         SetItemCount(GetItemCount() + 1);
  242.         SetSortColumn(m_sortColumn, m_sortDir);
  243.  
  244.         if (GetItemCount() == 1)
  245.             m_pOwner->SetIcon();
  246.     }
  247.     else if (op == USERCONTROL_CONNOP_CHANGEUSER)
  248.     {
  249.         int userid;
  250.         memcpy(&userid, pData + 2, 4);
  251.  
  252.         if (dwDataLength < 8)
  253.             return FALSE;
  254.  
  255.         std::map<int, CConnectionData*>::iterator iter = m_connectionDataMap.find(userid);
  256.         if (iter == m_connectionDataMap.end())
  257.             return FALSE;
  258.  
  259.         CConnectionData* pConnectionData = iter->second;
  260.  
  261.         unsigned int pos = 6;
  262.  
  263.         unsigned int len = pData[pos] * 256 + pData[pos+1];
  264.         pos += 2;
  265.         if ((pos + len) > dwDataLength)
  266.             return FALSE;
  267.  
  268.         char* user = new char[len + 1];
  269.         memcpy(user, pData + pos, len);
  270.         user[len] = 0;
  271.         pos += len;
  272. #ifdef _UNICODE
  273.         pConnectionData->columnText[COLUMN_USER] = ConvFromNetwork(user);
  274. #else
  275.         pConnectionData->columnText[COLUMN_USER] = ConvToLocal(ConvFromNetwork(user));
  276. #endif
  277.         delete [] user;
  278.  
  279.         if (pConnectionData->columnText[COLUMN_USER] == _T(""))
  280.         {
  281.             pConnectionData->itemImages[COLUMN_ID] = 5;
  282.             pConnectionData->columnText[COLUMN_USER] = _T("(not logged in)");
  283.         }
  284.         else
  285.         {
  286.             pConnectionData->itemImages[COLUMN_ID] = 4;
  287.         }
  288.         RedrawItems(pConnectionData->listIndex, pConnectionData->listIndex);
  289.         SetSortColumn(m_sortColumn, m_sortDir);
  290.     }
  291.     else if (op == USERCONTROL_CONNOP_REMOVE)
  292.     {
  293.         int userid;
  294.         memcpy(&userid, pData + 2, 4);
  295.  
  296.         std::map<int, CConnectionData*>::iterator iter = m_connectionDataMap.find(userid);
  297.         if (iter == m_connectionDataMap.end())
  298.             return FALSE;
  299.  
  300.         CConnectionData *pConnectionData = iter->second;
  301.  
  302.         m_connectionDataMap.erase(iter);
  303.         for (std::vector<CConnectionData*>::iterator iter2 = m_connectionDataArray.begin() + pConnectionData->listIndex + 1; iter2 != m_connectionDataArray.end(); iter2++)
  304.             (*iter2)->listIndex--;
  305.         m_connectionDataArray.erase(m_connectionDataArray.begin() + pConnectionData->listIndex);
  306.         delete pConnectionData;
  307.  
  308.         SetItemCount(m_connectionDataArray.size());
  309.  
  310.         if (!GetItemCount())
  311.             m_pOwner->SetIcon();
  312.     }
  313.     else if (op == USERCONTROL_CONNOP_TRANSFERINFO)
  314.     {
  315.         int userid;
  316.         memcpy(&userid, pData + 2, 4);
  317.  
  318.         if (dwDataLength < 7)
  319.             return FALSE;
  320.         std::map<int, CConnectionData*>::iterator iter = m_connectionDataMap.find(userid);
  321.         if (iter == m_connectionDataMap.end())
  322.             return FALSE;
  323.  
  324.         CConnectionData* pConnectionData = iter->second;
  325.  
  326.         pConnectionData->transferMode = pData[6];
  327.  
  328.         if (!pConnectionData->transferMode)
  329.         {
  330.             pConnectionData->physicalFile = _T("");
  331.             pConnectionData->logicalFile = _T("");
  332.             pConnectionData->currentOffset = 0;
  333.             pConnectionData->totalSize = -1;
  334.             pConnectionData->ResetSpeed();
  335.  
  336.             pConnectionData->columnText[COLUMN_TRANSFERPROGRESS] =  _T("");
  337.             pConnectionData->columnText[COLUMN_TRANSFERSPEED] =  _T("");
  338.         }
  339.         else
  340.         {
  341.             unsigned int pos = 7;
  342.             if ((pos + 2) > dwDataLength)
  343.                 return FALSE;
  344.  
  345.             unsigned int len = pData[pos] * 256 + pData[pos+1];
  346.             pos += 2;
  347.             if ((pos + len + 2) > dwDataLength)
  348.                 return FALSE;
  349.  
  350.             char* physicalFile = new char[len + 1];
  351.             memcpy(physicalFile, pData + pos, len);
  352.             physicalFile[len] = 0;
  353.             pos += len;
  354. #ifdef _UNICODE
  355.             pConnectionData->physicalFile = ConvFromNetwork(physicalFile);
  356. #else
  357.             pConnectionData->physicalFile = ConvToLocal(ConvFromNetwork(physicalFile));
  358. #endif
  359.             delete [] physicalFile;
  360.  
  361.             len = pData[pos] * 256 + pData[pos+1];
  362.             pos += 2;
  363.             if ((pos + len) > dwDataLength)
  364.                 return FALSE;
  365.  
  366.             char* logicalFile = new char[len + 1];
  367.             memcpy(logicalFile, pData + pos, len);
  368.             logicalFile[len] = 0;
  369.             pos += len;
  370. #ifdef _UNICODE
  371.             pConnectionData->logicalFile = ConvFromNetwork(logicalFile);
  372. #else
  373.             pConnectionData->logicalFile = ConvToLocal(ConvFromNetwork(logicalFile));
  374. #endif
  375.             delete [] logicalFile;
  376.  
  377.             if (pConnectionData->transferMode & 0x20)
  378.             {
  379.                 if ((pos + 8) > dwDataLength)
  380.                     return FALSE;
  381.  
  382.                 memcpy(&pConnectionData->currentOffset, pData + pos, 8);
  383.                 pos += 8;
  384.             }
  385.             else
  386.                 pConnectionData->currentOffset = 0;
  387.  
  388.             if (pConnectionData->transferMode & 0x40)
  389.             {
  390.                 if ((pos + 8) > dwDataLength)
  391.                     return FALSE;
  392.                 memcpy(&pConnectionData->totalSize, pData + pos, 8);
  393.                 pos += 8;
  394.             }
  395.             else
  396.                 pConnectionData->totalSize = -1;
  397.  
  398.             // Filter out indicator bits
  399.             pConnectionData->transferMode &= 0x9F;
  400.         }
  401.             
  402.         pConnectionData->columnText[COLUMN_TRANSFERINIT] =  m_showPhysical ? pConnectionData->physicalFile : pConnectionData->logicalFile;
  403.         pConnectionData->itemImages[COLUMN_TRANSFERINIT] =  pConnectionData->transferMode;
  404.  
  405.         RedrawItems(pConnectionData->listIndex, pConnectionData->listIndex);
  406.     }
  407.     else if (op == USERCONTROL_CONNOP_TRANSFEROFFSETS)
  408.     {
  409.         std::map<int, CConnectionData*>::iterator iter = m_connectionDataMap.begin();
  410.         unsigned char* p = pData + 2;
  411.         int max = dwDataLength - 12;
  412.         while ((p - pData) <= max)
  413.         {
  414.             int* userid = (int*)p;
  415.  
  416.             CConnectionData *pConnectionData;
  417.             while (true)
  418.             {
  419.                 if (iter == m_connectionDataMap.end())
  420.                     return FALSE;
  421.  
  422.                 if (iter->first == *userid)
  423.                 {
  424.                     pConnectionData = iter->second;
  425.                     break;
  426.                 }
  427.  
  428.                 iter++;
  429.             }
  430.             __int64* currentOffset = (__int64*)(p + 4);
  431.  
  432.             pConnectionData->AddBytes((int)(*currentOffset - pConnectionData->currentOffset));
  433.             pConnectionData->currentOffset = *currentOffset;
  434.  
  435.             CString str;
  436.             if (pConnectionData->totalSize != -1)
  437.             {
  438.                 double percent = (double)pConnectionData->currentOffset / pConnectionData->totalSize * 100;
  439.                 str.Format(_T("%s bytes (%1.1f%%)"), makeUserFriendlyString(pConnectionData->currentOffset).GetString(), percent);
  440.             }
  441.             else
  442.                 str.Format(_T("%s bytes"), makeUserFriendlyString(pConnectionData->currentOffset).GetString());
  443.             pConnectionData->columnText[COLUMN_TRANSFERPROGRESS] =  str;
  444.  
  445.             if (pConnectionData->speed > 1024 * 1024)
  446.                 str.Format(_T("%1.1f MB/s"), (double)pConnectionData->speed / 1024 / 1024);
  447.             else if (pConnectionData->speed > 1024)
  448.                 str.Format(_T("%1.1f KB/s"), (double)pConnectionData->speed / 1024);
  449.             else
  450.                 str.Format(_T("%1.1f bytes/s"), (double)pConnectionData->speed);
  451.             pConnectionData->columnText[COLUMN_TRANSFERSPEED] =  str;
  452.             
  453.             p += 12;
  454.         }
  455.         RedrawItems(GetTopIndex(), GetTopIndex() + GetCountPerPage());
  456.     }
  457.  
  458.     return TRUE;
  459. }
  460.  
  461. void CUsersListCtrl::OnContextmenuKick() 
  462. {
  463.     if (AfxMessageBox(_T("Do you really want to kick the selected user?"), MB_ICONQUESTION|MB_YESNO)!=IDYES)
  464.         return;
  465.     POSITION pos = GetFirstSelectedItemPosition();
  466.     while (pos)
  467.     {
  468.         int nItem = GetNextSelectedItem(pos);
  469.         
  470.         CConnectionData *data = m_connectionDataArray[nItem];
  471.         
  472.         unsigned char buffer[5];
  473.         buffer[0]=USERCONTROL_KICK;
  474.         memcpy(buffer+1, &data->userid, 4);
  475.         m_pOwner->SendCommand(3, &buffer, 5);
  476.     }    
  477. }
  478.  
  479. void CUsersListCtrl::OnContextmenuBan() 
  480. {
  481.     if (AfxMessageBox(_T("Do you really want to kick the selected user and ban his IP address?"), MB_ICONQUESTION|MB_YESNO)!=IDYES)
  482.         return;
  483.     POSITION pos = GetFirstSelectedItemPosition();
  484.     while (pos)
  485.     {
  486.         int nItem = GetNextSelectedItem(pos);
  487.         
  488.         CConnectionData *data = m_connectionDataArray[nItem];
  489.         
  490.         unsigned char buffer[5];
  491.         buffer[0] = USERCONTROL_BAN;
  492.         memcpy(buffer+1, &data->userid, 4);
  493.         m_pOwner->SendCommand(3, &buffer, 5);
  494.     }    
  495. }
  496.  
  497. void CUsersListCtrl::OnContextMenu(CWnd* pWnd, CPoint point) 
  498. {
  499.     CMenu menu;
  500.     menu.LoadMenu(IDR_USERVIEWCONTEXT);
  501.  
  502.     CMenu* pPopup = menu.GetSubMenu(0);
  503.     ASSERT(pPopup != NULL);
  504.     CWnd* pWndPopupOwner = this;
  505.     //while (pWndPopupOwner->GetStyle() & WS_CHILD)
  506.     //    pWndPopupOwner = pWndPopupOwner->GetParent();
  507.  
  508.     POSITION pos = GetFirstSelectedItemPosition();
  509.     if (!pos)
  510.     {
  511.         pPopup->EnableMenuItem(ID_USERVIEWCONTEXT_KICK, MF_GRAYED);
  512.         pPopup->EnableMenuItem(ID_USERVIEWCONTEXT_BAN, MF_GRAYED);
  513.     }
  514.         
  515.     pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
  516.         pWndPopupOwner);
  517. }
  518.  
  519. BOOL CUsersListCtrl::ParseUserControlCommand(unsigned char *pData, DWORD dwDataLength)
  520. {
  521.     int type = *pData;
  522.     if (type < 0 || type > 4)
  523.     {
  524.         m_pOwner->ShowStatus(_T("Protocol error: Invalid data"), 1);
  525.         return FALSE;
  526.     }
  527.     switch (type)
  528.     {
  529.     case USERCONTROL_GETLIST:
  530.         if (dwDataLength < 3)
  531.             return FALSE;
  532.         else
  533.         {
  534.             for (std::vector<CConnectionData*>::iterator iter = m_connectionDataArray.begin(); iter != m_connectionDataArray.end(); iter++)
  535.                 delete *iter;
  536.  
  537.             m_connectionDataMap.clear();
  538.             m_connectionDataArray.clear();
  539.             
  540.             int num = pData[1] * 256 + pData[2];
  541.             unsigned int pos = 3;
  542.             for (int i = 0; i < num; i++)
  543.             {
  544.                 if ((pos + 6) > dwDataLength)
  545.                     return FALSE;
  546.                 CConnectionData* pConnectionData = new CConnectionData;;
  547.                 memcpy(&pConnectionData->userid, pData+pos, 4);
  548.                 pos += 4;
  549.                 int len = pData[pos] * 256 + pData[pos+1];
  550.                 pos+=2;
  551.                 if (pos+len > dwDataLength)
  552.                 {
  553.                     delete pConnectionData;
  554.                     return FALSE;
  555.                 }
  556.  
  557.                 char* ip = new char[len + 1];
  558.                 memcpy(ip, pData + pos, len);
  559.                 ip[len] = 0;
  560.                 pos += len;
  561. #ifdef _UNICODE
  562.                 pConnectionData->columnText[COLUMN_IP] = ConvFromNetwork(ip);
  563. #else
  564.                 pConnectionData->columnText[COLUMN_IP] = ConvToLocal(ConvFromNetwork(ip));
  565. #endif
  566.                 delete [] ip;
  567.                 
  568.                 if ((pos+6) > dwDataLength)
  569.                 {
  570.                     delete pConnectionData;
  571.                     return FALSE;
  572.                 }
  573.                 memcpy(&pConnectionData->port, pData+pos, 4);
  574.                 
  575.                 pos+=4;
  576.                 
  577.                 len = pData[pos] * 256 + pData[pos+1];
  578.                 pos+=2;
  579.                 if ((pos + len + 1) > dwDataLength)
  580.                 {
  581.                     delete pConnectionData;
  582.                     return FALSE;
  583.                 }
  584.  
  585.                 char* user = new char[len + 1];
  586.                 memcpy(user, pData + pos, len);
  587.                 user[len] = 0;
  588.                 pos += len;
  589. #ifdef _UNICODE
  590.                 pConnectionData->columnText[COLUMN_USER] = ConvFromNetwork(user);
  591. #else
  592.                 pConnectionData->columnText[COLUMN_USER] = ConvToLocal(ConvFromNetwork(user));
  593. #endif
  594.                 delete [] user;
  595.  
  596.                 pConnectionData->transferMode = pData[pos++];
  597.  
  598.                 if (pConnectionData->transferMode)
  599.                 {
  600.                     if ((pos + 2) > dwDataLength)
  601.                     {
  602.                         delete pConnectionData;
  603.                         return FALSE;
  604.                     }
  605.                     len = pData[pos] * 256 + pData[pos+1];
  606.                     pos += 2;
  607.  
  608.                     if ((pos+len) > dwDataLength)
  609.                     {
  610.                         delete pConnectionData;
  611.                         return FALSE;
  612.                     }
  613.  
  614.                     char* physicalFile = new char[len + 1];
  615.                     memcpy(physicalFile, pData + pos, len);
  616.                     physicalFile[len] = 0;
  617.                     pos += len;
  618. #ifdef _UNICODE
  619.                     pConnectionData->physicalFile = ConvFromNetwork(physicalFile);
  620. #else
  621.                     pConnectionData->physicalFile = ConvToLocal(ConvFromNetwork(physicalFile));
  622. #endif
  623.                     delete [] physicalFile;
  624.  
  625.                     if ((pos + 2) > dwDataLength)
  626.                     {
  627.                         delete pConnectionData;
  628.                         return FALSE;
  629.                     }
  630.                     len = pData[pos] * 256 + pData[pos+1];
  631.                     pos += 2;
  632.  
  633.                     
  634.                     if ((pos+len) > dwDataLength)
  635.                     {
  636.                         delete pConnectionData;
  637.                         return FALSE;
  638.                     }
  639.  
  640.                     char* logicalFile = new char[len + 1];
  641.                     memcpy(logicalFile, pData + pos, len);
  642.                     logicalFile[len] = 0;
  643.                     pos += len;
  644. #ifdef _UNICODE
  645.                     pConnectionData->logicalFile = ConvFromNetwork(logicalFile);
  646. #else
  647.                     pConnectionData->logicalFile = ConvToLocal(ConvFromNetwork(logicalFile));
  648. #endif
  649.                     delete [] logicalFile;
  650.  
  651.                     if (pConnectionData->transferMode & 0x20)
  652.                     {
  653.                         memcpy(&pConnectionData->currentOffset, pData + pos, 8);
  654.                         pos += 8;
  655.                     }
  656.                     else
  657.                         pConnectionData->currentOffset = 0;
  658.  
  659.                     if (pConnectionData->transferMode & 0x40)
  660.                     {
  661.                         memcpy(&pConnectionData->totalSize, pData + pos, 8);
  662.                         pos += 8;
  663.                     }
  664.                     else
  665.                         pConnectionData->totalSize = -1;
  666.  
  667.                     // Filter out indicator bits
  668.                     pConnectionData->transferMode &= 0x9F;
  669.                 }
  670.                 else
  671.                 {
  672.                     pConnectionData->currentOffset = 0;
  673.                     pConnectionData->totalSize = -1;
  674.                 }
  675.  
  676.                 pConnectionData->columnText[COLUMN_ID].Format(_T("%06d"), pConnectionData->userid);
  677.                 m_connectionDataMap[pConnectionData->userid] = pConnectionData;
  678.                 pConnectionData->listIndex = m_connectionDataArray.size();
  679.                 m_connectionDataArray.push_back(pConnectionData);
  680.  
  681.                 if (pConnectionData->columnText[COLUMN_USER] == _T(""))
  682.                     pConnectionData->columnText[COLUMN_USER] = _T("(not logged in)");
  683.                 else
  684.                     pConnectionData->itemImages[COLUMN_ID] = 4;
  685.  
  686.                 
  687.                 pConnectionData->itemImages[COLUMN_TRANSFERINIT] = pConnectionData->transferMode;
  688.                 pConnectionData->columnText[COLUMN_TRANSFERINIT] = m_showPhysical ? pConnectionData->physicalFile : pConnectionData->logicalFile;
  689.             }
  690.             SetSortColumn(m_sortColumn, m_sortDir);
  691.             SetItemCount(m_connectionDataArray.size());
  692.             m_pOwner->SetIcon();
  693.         }
  694.         break;
  695.     case USERCONTROL_CONNOP:
  696.         return ProcessConnOp(pData, dwDataLength);
  697.         break;
  698.     case USERCONTROL_KICK:
  699.     case USERCONTROL_BAN:
  700.         break;
  701.     default:
  702.         m_pOwner->ShowStatus(_T("Protocol error: Specified usercontrol option not implemented"), 1);
  703.         return FALSE;
  704.         break;
  705.     }
  706.     return TRUE;
  707. }
  708.  
  709. void CUsersListCtrl::OnSize(UINT nType, int cx, int cy)
  710. {
  711.     CListCtrl::OnSize(nType, cx, cy);
  712. }
  713.  
  714. void CUsersListCtrl::SetDisplayPhysicalNames(bool showPhysical)
  715. {
  716.     m_showPhysical = showPhysical;
  717.  
  718.     // Iterate through all items and reset the transfer column text
  719.     for (std::vector<CConnectionData*>::iterator iter = m_connectionDataArray.begin(); iter != m_connectionDataArray.end(); iter++)
  720.     {
  721.         CConnectionData* pData = *iter;
  722.         pData->columnText[COLUMN_TRANSFERINIT] = showPhysical ? pData->physicalFile : pData->logicalFile;
  723.     }
  724.     RedrawItems(0, GetItemCount() - 1);
  725. }
  726.  
  727. void CUsersListCtrl::OnTimer(UINT_PTR nIDEvent)
  728. {
  729.     if (nIDEvent != m_nSpeedinfoTimer)
  730.         return;
  731.  
  732.     for (std::vector<CConnectionData*>::iterator iter = m_connectionDataArray.begin(); iter != m_connectionDataArray.end(); iter++)
  733.     {
  734.         CConnectionData* pConnectionData = *iter;
  735.         if (pConnectionData->transferMode)
  736.             pConnectionData->NextSpeed();
  737.     }
  738.     RedrawItems(0, GetItemCount() - 1);
  739. }
  740.  
  741. void CUsersListCtrl::SetSortColumn(int sortColumn /*=-1*/, int dir /*=-1*/)
  742. {
  743.     if (m_sortColumn == sortColumn || sortColumn == -1)
  744.     {
  745.         if (dir == -1)
  746.             m_sortDir = m_sortDir ? 0 : 1;
  747.         else
  748.             m_sortDir = dir ? 1 : 0;
  749.  
  750.         CHeaderCtrl *header = GetHeaderCtrl();
  751.         if (header)
  752.         {
  753.             HDITEM hdi;
  754.             hdi.mask = HDI_IMAGE | HDI_FORMAT;
  755.             hdi.fmt = HDF_IMAGE | HDF_STRING | HDF_BITMAP_ON_RIGHT;
  756.             hdi.iImage = m_sortDir + 1;
  757.             header->SetItem(m_sortColumn, &hdi);
  758.         }
  759.     }
  760.     else
  761.     {
  762.         if (dir == -1)
  763.             m_sortDir = 0;
  764.         else
  765.             m_sortDir = dir ? 1 : 0;
  766.  
  767.         if (sortColumn < 0 || sortColumn > 2)
  768.             sortColumn = 0;
  769.         
  770.         CHeaderCtrl *header = GetHeaderCtrl();
  771.         if (header)
  772.         {
  773.             HDITEM hdi;
  774.             hdi.mask = HDI_IMAGE | HDI_FORMAT;
  775.             hdi.fmt = HDF_STRING;
  776.             hdi.iImage = 0;
  777.             header->SetItem(m_sortColumn, &hdi);
  778.  
  779.             hdi.fmt = HDF_IMAGE | HDF_STRING | HDF_BITMAP_ON_RIGHT;
  780.             hdi.iImage = m_sortDir + 1;
  781.             header->SetItem(sortColumn, &hdi);
  782.         }
  783.  
  784.         m_sortColumn = sortColumn;
  785.     }
  786.  
  787.     if (m_connectionDataArray.size() < 2)
  788.         return;
  789.  
  790.     if (sortColumn == 1)
  791.         QSortList(m_sortDir, 0, m_connectionDataArray.size() - 1, CmpUser);
  792.     else if (sortColumn == 2)
  793.         QSortList(m_sortDir, 0, m_connectionDataArray.size() - 1, CmpIP);
  794.     else
  795.         QSortList(m_sortDir, 0, m_connectionDataArray.size() - 1, CmpUserid);
  796.  
  797.     for (unsigned int i = 0; i < m_connectionDataArray.size(); i++)
  798.         m_connectionDataArray[i]->listIndex = i;
  799.  
  800.     RedrawItems(0, m_connectionDataArray.size() - 1);
  801. }
  802.  
  803. void CUsersListCtrl::QSortList(const unsigned int dir, int anf, int ende, int (*comp)(const CUsersListCtrl *pList, unsigned int index, const CConnectionData* refData))
  804. {
  805.     int l = anf;
  806.     int r = ende;
  807.     const unsigned int ref = (l + r) / 2;
  808.     const CConnectionData* refData = m_connectionDataArray[ref];
  809.     do
  810.     {
  811.         if (!dir)
  812.         {
  813.             while ((comp(this, l, refData) < 0) && (l<ende)) l++;
  814.             while ((comp(this, r, refData) > 0) && (r>anf)) r--;
  815.         }
  816.         else
  817.         {
  818.             while ((comp(this, l, refData) > 0) && (l<ende)) l++;
  819.             while ((comp(this, r, refData) < 0) && (r>anf)) r--;
  820.         }
  821.         if (l<=r)
  822.         {
  823.             CConnectionData* tmp = m_connectionDataArray[l];
  824.             m_connectionDataArray[l] = m_connectionDataArray[r];
  825.             m_connectionDataArray[r] = tmp;
  826.             l++;
  827.             r--;
  828.         }
  829.     } 
  830.     while (l<=r);
  831.  
  832.     if (anf<r) QSortList(dir, anf, r, comp);
  833.     if (l<ende) QSortList(dir, l, ende, comp);
  834. }
  835.  
  836. int CUsersListCtrl::CmpUserid(const CUsersListCtrl *pList, unsigned int index, const CConnectionData* refData)
  837. {
  838.     const CConnectionData* data = pList->m_connectionDataArray[index];
  839.  
  840.     if (data->userid > refData->userid)
  841.         return 1;
  842.     else if (data->userid < refData->userid)
  843.         return -1;
  844.  
  845.     return 0;
  846. }
  847.  
  848. int CUsersListCtrl::CmpUser(const CUsersListCtrl *pList, unsigned int index, const CConnectionData* refData)
  849. {
  850.     const CConnectionData* data = pList->m_connectionDataArray[index];
  851.  
  852.     int res = data->columnText[COLUMN_USER].CompareNoCase(refData->columnText[COLUMN_USER]);
  853.     if (res)
  854.         return res;
  855.  
  856.     if (data->userid > refData->userid)
  857.         return 1;
  858.     else if (data->userid < refData->userid)
  859.         return -1;
  860.  
  861.     return 0;
  862. }
  863.  
  864. int CUsersListCtrl::CmpIP(const CUsersListCtrl *pList, unsigned int index, const CConnectionData* refData)
  865. {
  866.     const CConnectionData* data = pList->m_connectionDataArray[index];
  867.  
  868.     int res = data->columnText[COLUMN_IP].CompareNoCase(refData->columnText[COLUMN_IP]);
  869.     if (res)
  870.         return res;
  871.  
  872.     if (data->userid > refData->userid)
  873.         return 1;
  874.     else if (data->userid < refData->userid)
  875.         return -1;
  876.  
  877.     return 0;
  878. }
  879.  
  880. void CUsersListCtrl::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult)
  881. {
  882.     LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
  883.     LV_ITEM* pItem= &(pDispInfo)->item;
  884.  
  885.     if (static_cast<int>(m_connectionDataArray.size()) <= pItem->iItem)
  886.         return;
  887.  
  888.     if (pItem->mask & LVIF_TEXT)
  889.     {
  890.         if (_tcslen(m_connectionDataArray[pItem->iItem]->columnText[pItem->iSubItem]) >= static_cast<size_t>(pItem->cchTextMax))
  891.         {
  892.             _tcsncpy(pItem->pszText, m_connectionDataArray[pItem->iItem]->columnText[pItem->iSubItem], pItem->cchTextMax - 4);
  893.             pItem->pszText[pItem->cchTextMax - 4] = '.';
  894.             pItem->pszText[pItem->cchTextMax - 3] = '.';
  895.             pItem->pszText[pItem->cchTextMax - 2] = '.';
  896.             pItem->pszText[pItem->cchTextMax - 1] = 0;
  897.         }
  898.         else
  899.             lstrcpy(pItem->pszText, m_connectionDataArray[pItem->iItem]->columnText[pItem->iSubItem]);
  900.     }
  901.     if (pItem->mask & LVIF_IMAGE)
  902.         pItem->iImage = m_connectionDataArray[pItem->iItem]->itemImages[pItem->iSubItem];
  903. }
  904.  
  905. void CUsersListCtrl::OnColumnclick(NMHDR* pNMHDR, LRESULT* pResult) 
  906. {
  907.     NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  908.     SetSortColumn(pNMListView->iSubItem);
  909.     
  910.     *pResult = 0;
  911. }
  912.